from copy import deepcopy
import pandas as pd
from jili.core.printlog import print
from jili.data.db import getdb_client
from jili.pos import pos_frame
import datetime

from jili.data.db import tradecal

class pos(pos_frame):
    def __init__(self, cash=100000000, fee=0.000125, ip="127.0.0.1",priceurl=r"G:\price",isdetail=False):
        super(pos,self).__init__(priceurl,cash,isdetail)
        self.fee = fee
        self.fee0=0.001
        self.buysignals = {}
        self.sellsignals = {}
        self.posnum = 0
        self.targetnum=10
        self.tradeNo=0
        self.prebars = {}
        self.ip = ip
        self.cashflow = [{"precash": cash, "balance": cash}]
        self.signal_count={"buy":0,"sell":0}
        self.trade_count = {"buy": 0, "sell": 0}
    def calc_avlfund(self):
        return self.fund["cash"]-self.holdcash
    def get_benck_net_add_time(self, index_obj):
        t = list(self.fund_his.keys())
        t.sort()
        rst = self.getbenckmark(index_obj, t)
        posrate_his = pd.Series(self.posrate_his)
        kd = pd.DataFrame(rst)
        kd["net"] = kd["CLOSE"].pct_change()
        kd["net"] = kd["net"] + 1
        kd['timekey'] = pd.to_datetime(kd['timekey'])
        kd.set_index('timekey', inplace=True)
        temp = kd["net"][posrate_his[posrate_his > 0].index]
        temp = temp.cumprod()
        temp = temp.reindex(t).fillna(method='ffill')
        temp = temp.fillna(1)
        temp = temp.to_list()
        return temp
    def buy(self, timekey, obj, price,qty=None,msg="",is_commission=False):
        """

        Args:
            timekey:
            obj:
            price:
            qty:
            posrate:
            amount:
            msg:
            is_commission: 下单价格是否包含 费用；默认不包含，包含时使用策略自动评估费用等级场景

        Returns:

        """
        if is_commission == False:
            fee=price*self.fee
            price = price * (1 + self.fee)
        else:
            fee=0
            price = price
        qty=round(qty)
        cash=self.calc_avlfund()
        amont0=qty*price
        self.tradeNo = self.tradeNo + 1
        balance = {"precash": cash, "date": timekey, "tradeNo": self.tradeNo}
        order=self.create_order()
        order0={"obj":obj,"bs":"buy","buyprice":price,"buyamount":amont0,"qty":qty,"opentimekey":timekey,"buymsg":msg,
               "buy_precash":cash,"targetnum":self.targetnum,"posnum":self.posnum,"posrate":self.posrate_limit}
        order.update(order0)
        order["fee"]=order["qty"]*fee
        if obj in self.pos.keys():
            p = self.pos[obj]["buy"]
            if p["qty"] == 0:
                qty = amont0 / price
                print("新增买入", timekey, obj, price, qty,amont0,msg)
                p["qty"] = qty
                p["costprice"] = price
                p["costamount"] = amont0
                p["detail"] = [order]
                p["highprice"] = price
                p["fee"] = p["fee"] + fee * p["qty"]
            else:
                qty = amont0 / price
                print("买入增仓", timekey, obj, price, qty,amont0,msg)
                amont1 = p["costamount"] + amont0
                p["qty"] = p["qty"] + qty
                p["costprice"] = amont1 / p["qty"]
                p["costamount"] = amont1
                p["detail"].append(order)
                p["fee"] = p["fee"] + fee * p["qty"]
            p["openvalue"] = p["openvalue"] + amont0
        else:
            qty=amont0 / price
            print("新增买入", timekey, obj, price,qty,amont0,msg)
            p=self.create_pos()
            p0={"obj":obj,"bs":"buy","costprice":price,"highprice":price,"costamount":amont0,"qty":qty,"close_pl":0,"closevalue":0,"openvalue":amont0,"detail":[order]}
            p.update(p0)
            self.pos[obj]={}
            self.pos[obj]["buy"] = p

        self.cash2pos(amont0)
        balance["amount"] = amont0
        balance["balance"] = cash
        balance.update({"targetnum": self.targetnum, "posnum": self.getposnum(), "posrate": self.posrate_limit})
        balance["msg"] = str(order)
        self.cashflow.append(balance)
        self.trade_count["buy"] = self.trade_count["buy"] + 1
    def sell(self, timekey, obj, price,qty,msg="",is_commission=False):
        if obj in self.pos.keys():
            p = self.pos[obj]["buy"]
            qty=round(qty)
            p["qty"]=round(p["qty"])
            if p["qty"] > 0:
                posrate=qty/p["qty"]
                if posrate > 0.99:
                    posrate = 1
                pl = 0
                value = 0
                if qty == p["qty"]:
                    print("全部卖出", timekey, obj, price, qty,posrate,msg,p["qty"])
                    for i in p["detail"]:
                        self.tradeNo = self.tradeNo + 1
                        order0 = deepcopy(i)
                        order = {}
                        order["sellprice"] = price
                        order["closetimekey"] = timekey
                        order["buyamount"] = i["qty"] * i["buyprice"]
                        if is_commission == False:
                            fee= i["qty"] * price * (self.fee+self.fee0)
                            order["pl"] = i["qty"] * (price * (1 - self.fee-self.fee0) - i["buyprice"])
                            order["sellamount"] = i["qty"] * price * (1 - self.fee-self.fee0)
                            order["closeamount"] =order["sellamount"]
                        else:
                            fee=0
                            order["pl"] = i["qty"] * (price - i["buyprice"])
                            order["sellamount"] = i["qty"] * price
                            order["closeamount"] = order["sellamount"]
                        order["plr"] = order["pl"] / order["buyamount"]
                        order["fee"]=(order["buyamount"]/i["buyamount"])*i["fee"]+fee
                        order["sellmsg"] = msg
                        pl = pl + order["pl"]
                        value = value + order["sellamount"]
                        precash = self.calc_avlfund()
                        #self.check_calcpl(order["pl"], order["sellamount"])
                        cash=self.pos2cash(order["sellamount"])
                        order0.update(order)
                        self.orders_his.append(order0)
                        balance = {"precash": precash, "date": timekey, "tradeNo": self.tradeNo}
                        balance["amount"] = -order["sellamount"]
                        balance["balance"] = cash
                        balance.update(
                            {"targetnum": self.targetnum, "posnum": 1, "posrate": self.posrate_limit})
                        balance["msg"] = str(order)
                        self.cashflow.append(balance)
                    p["qty"] = 0
                    p["detail"] = []
                    p["pl"] = 0
                    p["value"] = 0
                    p["highprice"] = 0
                else:
                    print("部分卖出", timekey, obj, price,qty, posrate,msg,p["qty"])
                    if len(p["detail"]) == 1:
                        self.tradeNo = self.tradeNo + 1
                        i = p["detail"][0]
                        order0 = deepcopy(i)
                        order = {}
                        order["qty"] = qty
                        order["sellprice"] = price
                        order["closetimekey"] = timekey
                        order["buyamount"] = qty * i["buyprice"]
                        if is_commission == False:
                            fee=qty * price * (self.fee+self.fee0)
                            order["pl"] = qty * (price * (1 - self.fee-self.fee0) - i["buyprice"])
                            order["sellamount"] = qty * price * (1 - self.fee-self.fee0)
                            order["closeamount"] = order["sellamount"]
                        else:
                            fee=0
                            order["pl"] = qty * (price - i["buyprice"])
                            order["sellamount"] = qty * price
                            order["closeamount"] = order["sellamount"]
                        order["plr"] = order["pl"] / order["buyamount"]
                        order["fee"] = (order["buyamount"]/order0["buyamount"])*order0["fee"] + fee
                        order["sellmsg"] = msg
                        pl = pl + order["pl"]
                        value = value + order["sellamount"]
                        i["qty"] = p["qty"] - qty
                        p["qty"] = i["qty"]
                        if is_commission == False:
                            p["pl"] = p["qty"] * (price * (1 - self.fee-self.fee0) - i["buyprice"])
                            p["value"] = p["qty"] * price * (1 - self.fee-self.fee0)
                        else:
                            p["pl"] = p["qty"] * (price - i["buyprice"])
                            p["value"] = p["qty"] * price
                        precash=self.calc_avlfund()
                        #self.check_calcpl(order["pl"], order["sellamount"])
                        cash=self.pos2cash(order["sellamount"])
                        order0.update(order)
                        self.orders_his.append(order0)
                        balance = {"precash": precash, "date": timekey, "tradeNo": self.tradeNo}
                        balance["amount"] = -order["sellamount"]
                        balance["balance"] = cash
                        balance.update(
                            {"targetnum": self.targetnum, "posnum": 1, "posrate": self.posrate_limit})
                        balance["msg"] = str(order)
                        #self.tradeamount_total = self.tradeamount_total + abs(balance["amount"])
                        self.cashflow.append(balance)
                    else:
                        while qty > 0:
                            i = p["detail"].pop(0)
                            if i["qty"] <= qty:
                                qty0 = i["qty"]
                            else:
                                qty0 = qty
                            self.tradeNo = self.tradeNo + 1
                            order0 = deepcopy(i)
                            order = {}
                            order["qty"] = qty0
                            order["sellprice"] = price
                            order["buyamount"] = qty0 * i["buyprice"]
                            order["closetimekey"] = timekey
                            if is_commission == False:
                                order["pl"] = qty0 * (price * (1 - self.fee-self.fee0) - i["buyprice"])
                                order["sellamount"] = qty0 * price * (1 - self.fee-self.fee0)
                                order["closeamount"] = order["sellamount"]
                            else:
                                order["pl"] = qty0 * (price - i["buyprice"])
                                order["sellamount"] = qty0 * price
                                order["closeamount"] = order["sellamount"]
                            order["plr"] = order["pl"] / order["buyamount"]
                            # order["fee"] = (order["buyamount"] / order0["buyamount"]) * order0["fee"] + fee
                            order["sellmsg"] = msg
                            pl = pl + order["pl"]
                            value = value + order["sellamount"]
                            precash = self.calc_avlfund()
                            #self.check_calcpl(order["pl"], order["sellamount"])
                            cash = self.pos2cash(order["sellamount"])
                            order0.update(order)
                            self.orders_his.append(order0)
                            balance = {"precash": precash, "date": timekey, "tradeNo": self.tradeNo}
                            balance["amount"] = -order["sellamount"]
                            balance["balance"] = cash
                            balance.update(
                                {"targetnum": self.targetnum, "posnum": 1, "posrate": self.posrate_limit})
                            balance["msg"] = str(order)
                            #self.tradeamount_total = self.tradeamount_total + abs(balance["amount"])
                            self.cashflow.append(balance)
                            qty = qty - i["qty"]
                            if qty < 0:
                                i["qty"] = i["qty"] - qty0
                                p["detail"].insert(0, i)
                        p["qty"] = p["qty"] * (1 - posrate)
                        if is_commission == False:
                            fee=p["qty"] * price *  (self.fee+self.fee0)
                            p["pl"] = p["qty"] * (price * (1 - self.fee-self.fee0) - i["buyprice"])
                            p["value"] = p["qty"] * price * (1 - self.fee-self.fee0)
                        else:
                            fee=0
                            p["pl"] = p["qty"] * (price - i["buyprice"])
                            p["value"] = p["qty"] * price
                p["close_pl"] = p["close_pl"] + pl
                p["costamount"] = p["costamount"] * (1 - posrate)
                p["closevalue"] = p["closevalue"] + value
                p["fee"] = p["fee"] + fee
                self.trade_count["sell"] = self.trade_count["sell"] + 1
    def calc_fund(self):
        value=0
        for obj,v in self.pos.items():
            for bs,p in v.items():
                if p["qty"] > 0:
                    t = self.bar_pool[obj]
                    #price = t["close"] * (1 - self.fee)
                    price = t["close"]
                    if "close_pl" not in p.keys():
                        p["close_pl"] = 0
                        p["closevalue"] = 0
                    p["value"] = price * p["qty"]
                    p["pl"] = p["value"] - p["costamount"]
                    value = value + p["value"]
                    if price > p["highprice"]:
                        p["highprice"] = price
        self.fund["margin"]=value
        self.fund["balance"]=self.fund["margin"]+self.fund["cash"]
        return self.fund
    def getfundpos(self,date, data):
        self.calc_fund()
        return self.fund,self.pos
    def ondayend(self, date, data={}):#默认第一天净值处理
        d = datetime.datetime(date.year, date.month, date.day)
        self.timekey=d
        if d not in self.fund_his.keys():
            if not self.fund_his:
                t1 = datetime.datetime(date.year, date.month, date.day) - datetime.timedelta(days=1)
                self.fund_his[t1] = self.cash0
                self.posrate_his[t1] = 0
                self.return_his[t1]=0
            prebalance = self.fund["prebalance"]
            if data:
                self.bar_pool.update(data)
            self.calc_fund()
            t={}
            pos0=deepcopy(self.pos)
            for obj,v in pos0.items():
                t0={}
                for bs, p in v.items():
                    if p["qty"] > 0:
                        t0[bs]=p
                if t0:
                    t[obj]=t0
            self.pos_his[date] = t
            self.pos=t
            cashin=self.fund["cashin"]
            fund0=self.fund["balance"]
            if self.maxfund < fund0:
                self.maxfund = fund0
            self.fund_his[date] = fund0
            self.curr_return = (fund0 - self.cash0- self.cashin_total) / (self.cash0+ self.cashin_total)
            self.return_byday = (fund0 - prebalance-cashin) / (prebalance + cashin)
            self.return_his[date] = self.return_byday
            self.curr_posrate = (fund0 - self.fund["cash"]) / fund0
            self.posrate_his[date] = self.curr_posrate
            self.fund["prebalance"]=fund0
            self.fund["cashin"]=0

            print("日终计算",d, date, self.curr_posrate, fund0, self.curr_return,self.return_byday)
        if data:
            self.prebars = data
    def update_pos(self,obj,pos,r):
        if obj in self.pos.keys():
            if "buy" in self.pos[obj].keys():
                if isinstance(pos,dict):
                    qty=pos["qty"]
                    price=pos["costprice"]
                else:
                    qty = pos["qty"]
                    price = pos["costprice"]
                if qty!=self.pos[obj]["buy"]["qty"]:
                    print("可能发生除权除息，请确认，更新持仓")
                    self.pos[obj]["buy"]["qty"]=qty
                    self.pos[obj]["buy"]["costprice"] = price
                    for o in self.pos[obj]["buy"]["costprice"]["detail"]:
                        o["qty"]=o["qty"]*r
                        o["buyprice"]=o["buyprice"]*r

if __name__=="__main__":
    pos0=pos(cash=100*10000,isdetail=True)
